#ifndef __SELECT_SVR_H
#define __SELECT_SVR_H
#include "Sock.hpp"
#include "Log.hpp"
#include <iostream>
#include <string>
#include <sys/select.h>
#include <sys/time.h>
#include <vector>

#define BITS 8
#define NUM (sizeof(fd_set) * BITS)
#define FD_NONE -1

using namespace std;

class SelectServer
{
public:
    SelectServer(const uint16_t &port=8080)
        :_port(port)
    {
        _listensock=Sock::Socket();
        Sock::Bind(_listensock,_port);
        Sock::Listen(_listensock);
        logMessage(DEBUG,"%s","create base socket success");
        for(int i=0;i<NUM;i++){
            _fd_array[i]=FD_NONE;
        }
        _fd_array[0]=_listensock;
    }
    void Start()
    {
        while(true)
        {
            DebugPrint();
            fd_set rfds;
            FD_ZERO(&rfds);
            int maxfd=_listensock;
            for(int i=0;i<NUM;i++)
            {
                if(_fd_array[i]!=FD_NONE)
                {
                    FD_SET(_fd_array[i],&rfds);
                    if(maxfd<_fd_array[i]) maxfd=_fd_array[i];
                }
                int n=select(maxfd+1,&rfds,nullptr,nullptr,nullptr);
                switch(n)
                {
                    case 0:
                        logMessage(DEBUG,"%s","select timeout");
                        break;
                    case -1:
                        logMessage(ERROR,"%s","select error");
                        break;
                    default:
                        logMessage(DEBUG,"get a new link event");
                        HandlerEvent(rfds);
                        break;
                }
            }
        }
    }
private:
    void HandlerEvent(const fd_set &rfds)
    {
        for(int i=0;i<NUM;i++)
        {
            if(_fd_array[i]!=FD_NONE&&FD_ISSET(_fd_array[i],&rfds))
            {
                if(_fd_array[i]==_listensock)
                    Accepter();
                else
                    Recver(i);
            }
        }
    }
    void Accepter()
    {
        string clientip;
        uint16_t clientport;
        int sock=Sock::Accept(_listensock,&clientip,&clientport);
        if(sock<0)
        {
            logMessage(WARNING,"%s","accept error");
            return;
        }
        logMessage(DEBUG,"get a new line success : [%s:%d] : %d",clientip.c_str(),clientport,sock);
        int pos=1;
        for(;pos<NUM&&_fd_array[pos]!=FD_NONE;pos++);
        if(pos==NUM)
        {
            logMessage(WARNING, "select server full, close: %d", sock);
            close(sock);
        } else {
            _fd_array[pos] = sock;
        }
    }
    // 处理接收数据
    void Recver(int pos)
    {
        logMessage(DEBUG, "message in, get IO event: %d", _fd_array[pos]);

        char buffer[1024];
        int n = recv(_fd_array[pos], buffer, sizeof(buffer) - 1, 0);
        if (n > 0)
        {
            buffer[n] = 0;
            logMessage(DEBUG, "client[%d]# %s", _fd_array[pos], buffer);
        }
        else if (n == 0)
        { // 客户端关闭连接
            logMessage(DEBUG, "client[%d] quit, me too...", _fd_array[pos]);
            close(_fd_array[pos]);
            _fd_array[pos] = FD_NONE;
        }
        else
        {
            logMessage(WARNING, "%d sock recv error, %d : %s", _fd_array[pos], errno, strerror(errno));
            close(_fd_array[pos]);
            _fd_array[pos] = FD_NONE;
        }
    }
    void DebugPrint()
    {
        cout<<"_fd_array[]";
        for(int i=0;i<NUM;i++)
        {
            if(_fd_array[i]!=FD_NONE)
                cout<<_fd_array[i]<<" ";
        }
        cout<<endl;
    }

    uint16_t _port;
    int _listensock;
    int _fd_array[NUM];
};
#endif